'use strict';

import { UserType } from '../model/user'
import { Service } from 'egg'
const svgCaptcha = require('svg-captcha');
import { v4 } from 'uuid';

/**
 * 验证码缓存的KEY
 */
const VERIFICATION_CODE_REDIS_KEY = 'VERIFICATION_CODE_REDIS_KEY'

export default class UserService extends Service {

  /**
   * 相应的用户数据
   */
  resUserData(userData, other = {}) {
    return {
      name: userData.name,
      createTime: userData.createTime,
      type: userData.type,
      ...other
    }
  }

  /**
   * 获取验证码 Verification code
   */
  async verificationCode() {
    this.ctx.rotateCsrfSecret();
    const codeModel = svgCaptcha.create({
      width: 100,
      height: 40
    });
    const code = codeModel.text.toLocaleLowerCase();
    const uuid = v4()
    const { redis  } = this.ctx.app as any
    await redis.set(`${VERIFICATION_CODE_REDIS_KEY}_${uuid}`, code, 'EX', 1000 * 60 * 5);
    this.ctx.response.type = 'image/svg+xml';
    return {
      img: codeModel.data,
      uuid
    }
  }

  /**
   * 校验验证码
   */
  async checkVerificationCode(code: string, uuid: string) {
    const { redis  } = this.ctx.app as any
    const catchCode = await redis.get(`${VERIFICATION_CODE_REDIS_KEY}_${uuid}`);
    if (!catchCode) {
      throw '验证码过期，请刷新'
    }
    if (catchCode !== code.toLocaleLowerCase()) {
      throw '验证码错误';
    }
    // 清除校验码
    await redis.set(`${VERIFICATION_CODE_REDIS_KEY}_${uuid}`, '', 'EX', 1);
  }

  /**
   * 登录权限校验
   * @param project 项目
   * @param userData 用户数据
   */
  loingAuth(userData) {
    // 判断当前账户是否可用
    if (!userData.enabled) {
      throw '当前账号已经锁定，请联系管理员'
    }
  }

  /**
   * 登录
   * @param {*} param 登录参数
   */
  async login({ name, pass, code, uuid }) {
    const { User } = this.ctx.model as any;
    await this.checkVerificationCode(code, uuid)
    // 查找账号
    let userData = await User.findWithUser(name);
    // 如果没有找到用户直接抛出错误
    if (!userData) {
      // 判断当前是否有管理员账号
      const count = await User.findSuperAdminCount()
      if (count === 0) {
        userData = await this.create({
          name,
          type: UserType.SUPER_ADMIN,
          pass
        })
      } else {
        throw '当前用户未注册'; 
      }
    } else {
      this.loingAuth(userData)
      // 判断用户登录错误次数
      if (userData.loginErrNum >= 2) {
        throw '登录错误次数超过3次';
      }
      const passMD5 = this.ctx.w_tool.MD5(pass);
      // 判断账号密码是否正确
      if (passMD5 !== userData.pass) {
        // 记录登录错误加1
        await userData.addLoginErrNum();
        throw '密码错误';
      }
      // 清除登录错误
      userData.clearLoginErrNum();
    }
    // 存储用户数据到redis
    this.ctx.setReidsUserDataWithUser(userData)
    // 根据用户 ID 获取 token
    this.ctx.createToken(userData._id)
    return this.resUserData(userData);
  }

  /**
   * session登录
   */
  async sessionLogin() {
    const { ctx } = this
    // 获取用户数据
    const userData = await ctx.getUserData()
    if (!userData) {
      throw {
        status: 401,
        msg: '登录超时请重新登录'
      }
    }
    this.loingAuth(userData)
    const { PROJECT_ID } = this.ctx.w_get_cookie() as any
    const { project } = this.ctx.request.header
    const other: any = {}
    if (project === 'PROJECT' && PROJECT_ID && PROJECT_ID.length === 24) {
      if (userData.type === UserType.SUPER_ADMIN ||  userData.projects.includes(PROJECT_ID)) {
        // 获取项目
        const { Project } = this.ctx.model as any;
        other.currentProject = await Project.findWithID(PROJECT_ID)
      }
    }
    return this.resUserData(userData, other)
  }

  /**
   * 退出登录
   */
  async logut() {
    const { ctx } = this as any
    ctx.clearTokenWithUserId()
  }

  /**
   * 修改密码(修改当前账户的密码)
   */
  async updatePassword({ newPass, oldPass, code, uuid }) {
    const { ctx } = this
    // 获取用户数据
    const userData = await ctx.getUserData()
    const oldPassMd5 = this.ctx.w_tool.MD5(oldPass);
    await this.checkVerificationCode(code, uuid)
    if (oldPassMd5 !== userData.pass) {
      throw '旧密码不正确'
    }
    const newPassMd5 = this.ctx.w_tool.MD5(newPass);
    const { User } = this.ctx.model as any;
    await User.updateUser(userData._id, {
      pass: newPassMd5
    });
    this.logut()
  }

  /**
   * 修改密码(修改其他人的密码)
   */
  async changeOtherPassword({ newPass, code, id, uuid }) {
    const { ctx } = this as any
    // 获取用户数据
    const userData = await ctx.getUserData()
    await this.checkVerificationCode(code, uuid)
    if (userData._id === id) {
      throw '如果想修改自己的密码，请点击右上角修改'
    }
    const newPassMd5 = this.ctx.w_tool.MD5(newPass);
    const { User } = this.ctx.model as any;
    await User.updateUser(id, {
      pass: newPassMd5
    });
    // 清除这个人的 token 数据，强制他重新登陆
    ctx.clearTokenWithUserId(id)
  }

  /**
   * 创建用户
   */
  async create(userData) {
    const { User } = this.ctx.model;
    const { pass, type, name } = userData;
    const userModel = new User({
      name,
      createTime: new Date(),
      type,
      pass: this.ctx.w_tool.MD5(pass),
    })
    await userModel.save();
    return userModel
  }


  /**
   * 添加账号
   */
  async createAccount({ name, pass, code, type, uuid }) {
    const { User } = this.ctx.model as any;
    // 校验验证码
    await this.checkVerificationCode(code, uuid)
    // 超级管理员已经在中间件校验
    // 判断添加的账号是否存在
    let findUser = await User.findWithUser(name);
    if (findUser) {
      throw '当前用户名已经存在，请更改'
    }
    await this.create({ name, type, pass })
  }

  /**
   * 获取个数
   */
  async count() {
    const { User } = this.ctx.model as any;
    const { type } = this.ctx.query
    const other = type === 'ALL' ? {} : { type }
    return await User.findAllCount(this.ctx.query, other);
  }

  /**
	 * 获取所有用户
	 */
  async list() {
    const { User } = this.ctx.model as any;
    const { type } = this.ctx.query
    const other = type === 'ALL' ? {} : { type }
    return await User.findList(this.ctx.query, other);
  }

  /**
   * 修改用户状态
   */
  async userEnabled({ id, enabled }) {
    const { User } = this.ctx.model as any;
    const userModel = await User.findWithID(id)
    if (userModel.type === UserType.SUPER_ADMIN && !enabled) {
      throw '超级管理员不能禁用'
    }
    const upData: any = { enabled }
    enabled ? upData.loginErrNum = 0 : null
    await User.updateUser(id, upData);
    // 清除这个人的 token 数据，强制他重新登陆
    this.ctx.clearTokenWithUserId(id)
  }

  /**
	 * 删除用户
	 */
  async removeAccount(id) {
    const { ctx } = this
    // 获取用户数据
    const userData = await ctx.getUserData()
    if (id === userData._id) {
      throw '当前登录的账号不能删除'
    }
    const { User } = this.ctx.model as any;
    return await User.removeUser(id);
  }

  /**
	 * 添加项目
	 */
  async addProject({ projectId, userId }) {
    const { User } = this.ctx.model as any;
    await User.addProject(userId, projectId);
    this.ctx.clearRedisUserData(userId)
  }

  /**
	 * 删除项目
	 */
  async removeProject({ projectId, userId }) {
    const { User } = this.ctx.model as any;
    await User.removeProject(userId, projectId);
    this.ctx.clearRedisUserData(userId)
  }

  /**
   * 获取当前账号下面的项目列表
   */
  async projectList() {
    const { User } = this.ctx.model as any;
    const { ctx } = this
    const { _id } = await ctx.getUserData()
    const userModel = await User.projectList(_id)
    return userModel.projects
  }

  /**
   * 获取当前账号下面的项目列表
   */
  async resetPass(name: string) {
    const { User } = this.ctx.model as any;
    const userModel = await User.findWithUser(name)
    if (!userModel) {
      throw '当前账号未找到'
    }
    userModel.pass = this.ctx.w_tool.MD5('888888');
    await userModel.save()
    this.ctx.sendSuccess('OK');
  }
}
